import numpy as np
import random
import matplotlib.pyplot as plt
import math

def hanshu(Jm,T,JmNumber,POS,V):
    NIND=40                     #个体数目
    MAXGEN=500                  #最大遗传代数
    GGAP=0.9                    #代沟
    XOVR=0.8                    #交叉率
    MUTR=0.6                    #变异率
    gen=0                       #代计数器

    T_list = Tlist(POS,V)

    PNumber,MNumber = Jm.shape
    trace = np.zeros((2,MAXGEN))
    WNumber = PNumber*MNumber

    #初始化
    Number=np.zeros(PNumber)            #PNumber工件个数
    WPNumberTemp=np.zeros(PNumber)

    for i in range(PNumber):
        Number[i] = MNumber                 #MNumber工序个数

    Chrom = np.zeros((NIND,2*WNumber))
    for j in range(NIND):
        for i in range(PNumber):
            WPNumberTemp[i] = MNumber
        for i in range(WNumber):
            val = random.randint(1,PNumber)
            while WPNumberTemp[val-1] == 0:
                val = random.randint(1,PNumber)

            Chrom[j][i] = val
            WPNumberTemp[val-1] = WPNumberTemp[val-1] - 1

            Temp = Jm[val-1][MNumber-1-int(WPNumberTemp[val-1])]
            Tempstr = str(Temp)

            if Tempstr.isdigit():
                SizeTemp = 1
            else:
                SizeTemp = len(Temp)

            Chrom[j][i+WNumber] = random.randint(1,SizeTemp)

    PVal,ObjV,P,S = cal(Chrom,JmNumber,T,Jm)

    while gen < MAXGEN:
        FitnV = ranking(ObjV)

        SelCh = select(Chrom, FitnV, GGAP)

        SelCh = across(SelCh,XOVR)

        SelCh = aberranceJm(SelCh,MUTR,Jm,T)

        PVal,ObjVSel,P,S = cal(SelCh, JmNumber, T, Jm)

        Chrom,ObjV = reins(Chrom, SelCh, 1, 1, ObjV, ObjVSel)

        gen = gen + 1

        Min = ObjV[0][0]
        Mean = 0
        for i in range(NIND):
            if ObjV[i][0] < Min:
                Min = ObjV[i][0]
            Mean = Mean + ObjV[i][0]

        trace[0][gen-1] = Min
        trace[1][gen-1] = Mean/NIND

        if gen == 1:
            Val1 = np.zeros((PVal.shape[0],PVal.shape[1]))
            for i in range(PVal.shape[0]):
                for j in range(PVal.shape[1]):
                    Val1[i][j] = PVal[i][j]
            Val2 = np.zeros(len(P))
            for i in range(len(P)):
                Val2[i] = P[i]
            MinVal = Min
            STemp = np.zeros(len(S))
            for i in range(len(S)):
                STemp[i] = S[i]

        if MinVal > trace[0][gen-1]:
            Val1 = np.zeros((PVal.shape[0],PVal.shape[1]))
            for i in range(PVal.shape[0]):
                for j in range(PVal.shape[1]):
                    Val1[i][j] = PVal[i][j]
            Val2 = np.zeros(len(P))
            for i in range(len(P)):
                Val2[i] = P[i]
            MinVal = trace[0][gen-1]
            STemp = np.zeros(len(S))
            for i in range(len(S)):
                STemp[i] = S[i]

    for i in range(PVal.shape[0]):
        for j in range(PVal.shape[1]):
            PVal[i][j] = Val1[i][j]
    for i in range(len(P)):
        P[i] = Val2[i]
    for i in range(len(S)):
        S[i] = STemp[i]

    # 在此设置字体及大小
    #font = FontProperties(fname=r"D:\pythonwork\遗传算法\font\SimHei.ttf", size=14)
    ###画图
    X, Y1, Y2 = [], [], []
    for i in range(MAXGEN):
        X.append(i)
        Y1.append(trace[0][i])
        Y2.append(trace[1][i])

    fig1 = plt.figure(1)
    plt.rcParams['font.sans-serif'] = ['SimHei']        # 添加这条可以让图形显示中文
    plt.title(u'解与种群均值的变化')
    plt.xlabel(u'遗传代数')
    plt.ylabel(u'数值')
    plt.plot(X, Y1, color="red", linestyle="--", linewidth=0.5, label=u'解的变化')
    plt.plot(X, Y2, color="blue", linewidth=0.5, label=u'种群均值的变化')
    plt.legend(loc="best")

    fig2 = plt.figure(2)
    MP = np.zeros(PNumber*MNumber)      #5,3
    for i in range(PNumber*MNumber):
        MP[i] = S[PNumber*MNumber+i]    #区分

    VAL = np.zeros((JmNumber,PNumber))
    OPX1 = np.zeros((JmNumber,PNumber))               #4辆车，5架飞机
    OPX2 = np.zeros((JmNumber, PNumber))
    OPN = np.zeros((JmNumber, PNumber))
    CarN = np.zeros(JmNumber)
    for i in range(JmNumber):
        CarN[i] = 0

    #print(P)
    for i in range(WNumber):        #WNumber = 15
        val = int(P[i])
        b, a = divmod(val, 100)

        Temp = Jm[b - 1][a - 1]
        Tempstr = str(Temp)
        if Tempstr.isdigit():
            mText = Temp
        else:
            mText = Temp[int(MP[i]) - 1]

        x1 = PVal[0][i]
        x2 = PVal[1][i]

        #plotRec.plotRec(x1, x2, mText, val)
        VAL[mText-1][int(CarN[mText-1])] = val
        OPX1[mText-1][int(CarN[mText-1])] = x1
        OPX2[mText - 1][int(CarN[mText-1])] = x2
        OPN[mText - 1][int(CarN[mText-1])] = b
        CarN[mText - 1] = CarN[mText - 1] + 1



    for i in range(JmNumber):
        T_sum = 0
        for j in range(PNumber):
            if OPN[i][j] != 0:
                if j == 0:
                    T_sum = T_sum + T_list[0][int(OPN[i][j])]
                    OPX1[i][j] = round(OPX1[i][j] + T_sum,2)
                    OPX2[i][j] = round(OPX2[i][j] + T_sum,2)
                else:
                    T_sum = T_sum + T_list[int(OPN[i][j-1])][int(OPN[i][j])]
                    OPX1[i][j] = round(OPX1[i][j] + T_sum,2)
                    OPX2[i][j] = round(OPX2[i][j] + T_sum,2)

    T_result = 0
    for i in range(JmNumber):
        for j in range(PNumber):
            if T_result < OPX2[i][j]:
                T_result = OPX2[i][j]

    # print(VAL)
    OPX1 = OPX1.tolist()
    OPX2 = OPX2.tolist()
    OPN = OPN.tolist()
    for i in range(JmNumber):
        for j in range(PNumber):
            OPN[i][j] = int(OPN[i][j])
            if OPX1[i][j] == 0:
                OPX1[i][j] = int(OPX1[i][j])
                OPX2[i][j] = int(OPX2[i][j])
    #print("beginTime=")
    #print(OPX1)
    #print("endTime=")
    #print(OPX2)
    #print("name=")
    #print(OPN)          #OPX1[i][j]、OPX2[i][j]、OPN[i][j]连起来看，表示第i辆车为第OPN[i][j]辆飞机干活，时间为从OPX1[i][j]到OPX2[i][j]
    #
    for i in range(JmNumber):
        for j in range(PNumber):
            if OPN[i][j] != 0:
                x1 = OPX1[i][j]
                x2 = OPX2[i][j]
                mText = i + 1
                val = int(VAL[i][j])
                plotRec(x1, x2, mText, val)

    #print("保障结果：")
    #print("总时间："+ str(T_result) + "分钟")
    #
    line = []
    for i in range(JmNumber):
        OPstr = ''
        for j in range(PNumber):
            if OPN[i][j] != 0:
                if j != 0:
                    OPstr = OPstr + ','
                OPstr = OPstr + '从第' + str(round(OPX1[i][j],2)) + '分钟到第' + str(round(OPX2[i][j],2)) + '分钟给' + str(int(OPN[i][j])) + '号飞机'
                if i <= 1:
                    OPstr = OPstr + '加油'
                if i == 2:
                    OPstr = OPstr + '加气'
                if i == 3:
                    OPstr = OPstr + '维修'
        line.append(str(i+1) + '号车：' + OPstr)
        #print(str(i+1) + '号车：' + OPstr)

    plt.rcParams['font.sans-serif'] = ['SimHei']        # 添加这条可以让图形显示中文
    plt.title(u'保障调度')
    plt.xlabel(u'保障时间')
    plt.ylabel(u'保障车辆')
    plt.text(14,0.4,'最小时间：'+str(T_result),weight='bold',color='red')
    plt.show()
    #fig1.savefig('种群均值.png')
    #fig2.savefig('保障流程.png')
    #fig2.savefig('../dist/assets/bzlc.png')

    print({"code": 1, "msg": "", "beginTime": OPX1, "endTime": OPX2, "totalTime": T_result, "name": OPN, "line": line}, end="")

def Tlist(POS,V):
    PNumber = POS.shape[0]

    T_list = np.zeros((PNumber,PNumber))
    for i in range(PNumber):
        for j in range(PNumber):
            T = math.sqrt((POS[i][0]-POS[j][0])**2 + (POS[i][1]-POS[j][1])**2)
            T_list[i][j] = round(T/V,2)

    return T_list

def cal(Chrom,JmNumber,T,Jm):
    NIND,NvarP = Chrom.shape
    ObjV = np.zeros((NIND,1))
    PNumber,MNumber = Jm.shape

    for i in range(NIND):
        S = np.zeros(NvarP)
        for j in range(NvarP):
            S[j] = Chrom[i][j]

        P = calp(S,PNumber)
        PVal = caltime(S,P,JmNumber,T,Jm)
        TVal = 0
        for j in range(PVal.shape[0]):
            for k in range(PVal.shape[1]):
                if TVal < PVal[j][k]:
                    TVal = PVal[j][k]

        ObjV[i][0] = TVal

        if i==0:
            Val1 = PVal
            Val2 = P
            MinVal = ObjV[i][0]
            STemp = S

        if MinVal > ObjV[i][0]:
            Val1 = PVal
            Val2 = P
            MinVal = ObjV[i][0]
            STemp = S

    PVal = Val1
    P = Val2
    S = STemp

    return PVal,ObjV,P,S

def calp(S,PNumber):
    WNumber = len(S)
    WNumber = int(WNumber/2)

    temp = np.zeros(PNumber)       #5
    P = np.zeros(WNumber)           #15

    for i in range(WNumber):
        temp[int(S[i])-1] = temp[int(S[i])-1] + 1
        P[i] = int(S[i])*100 + temp[int(S[i])-1]

    return P

def caltime(S,P,JmNumber,T,Jm):
    PNumber,MNumber = Jm.shape

    M = np.zeros(PNumber*MNumber)
    for i in range(PNumber*MNumber):
        M[i] = S[PNumber*MNumber+i]

    WNumber = len(P)

    TM = np.zeros(JmNumber)
    TP = np.zeros(PNumber)
    PVal = np.zeros((2,WNumber))

    for i in range(WNumber):
        val = int(P[i])
        b,a = divmod(val,100)

        Temp = Jm[b-1][a-1]
        Tempstr = str(Temp)
        if Tempstr.isdigit():
            m = Temp
        else:
            m = Temp[int(M[i]) - 1]

        Temp = T[b-1][a-1]
        if Tempstr.isdigit():
            t = Temp
        else:
            t = Temp[int(M[i]) - 1]

        TMval = TM[m-1]
        TPval = TP[b-1]

        if TMval > TPval:
            val = TMval
        else:
            val = TPval

        PVal[0][i] = val
        PVal[1][i] = val + t

        TM[m-1] = PVal[1][i]
        TP[b-1] = PVal[1][i]

    return PVal

def ranking(ObjV):
    Nind = ObjV.shape[0]

    RFun = np.zeros((Nind,1))
    for i in range(Nind):
        RFun[i][0] = 2*i/(Nind-1)

    num_list = -ObjV
    ix = sorted(range(len(num_list)), key=lambda k: num_list[k])

    Sorted = np.zeros(Nind)
    for i in range(Nind):
        Sorted[i] = ObjV[ix[i]][0]

    start = 0
    FitnVSub = np.zeros(Nind)

    Sorted1 = np.zeros(Nind)
    for i in range(Nind - 1):
        if Sorted[i] != Sorted[i + 1]:
            Sorted1[i] = 1

    j = 0
    Sorted2 = []
    for i in range(Nind - 1):
        if Sorted1[i] == 1:
            Sorted2.append(j)
        j = j + 1
    Sorted2.append(Nind - 1)

    for i in range(len(Sorted2)):
        end = Sorted2[i]
        sum = 0
        for j in range(end-start+1):
            sum = sum + RFun[start+j]
        for j in range(end-start+1):
            FitnVSub[start+j] = sum/(end-start+1)
        start = end + 1

    num_list = ix
    uix = sorted(range(len(num_list)), key=lambda k: num_list[k])

    FitnV = []
    FitnV.append(FitnVSub[uix])
    FitnV = FitnV[0]

    return FitnV

def select(Chrom, FitnV, GGAP):
    Nind,Nvar = Chrom.shape

    NSel = max(int(Nind*GGAP+0.5),2)

    ChrIx = rws(FitnV, NSel)

    SelCh = np.zeros((NSel,Nvar))
    for i in range(NSel):
        for j in range(Nvar):
            SelCh[i][j] = Chrom[int(ChrIx[i])][j]

    return SelCh

def rws(FitnV,Nsel):
    Nind = len(FitnV)
    sum = 0
    cumfit = np.zeros(Nind)
    for i in range(Nind):
        sum = sum + FitnV[i]
        cumfit[i] = sum

    Nsell = np.random.rand(Nsel)
    trials = Nind * Nsell

    Mf = np.zeros((Nind,Nsel))
    Mt = np.zeros((Nind,Nsel))

    for j in range(Nsel):
        for i in range(Nind):
            Mf[i][j] = cumfit[i]
    for i in range(Nind):
        for j in range(Nsel):
            Mt[i][j] = trials[j]

    Mff = np.zeros((Nind, Nsel))
    for i in range(Nsel):
        Mff[0][i] = 0
    for i in range(Nsel):
        for j in range(Nind-1):
            Mff[j+1][i] = Mf[j][i]

    result = []
    for i in range(Nind):
        for j in range(Nsel):
            if Mff[i][j] <= Mt[i][j] and Mt[i][j] < Mf[i][j]:
                result.append([i,j])

    NewChrIx = np.zeros(Nsel)
    for i in range(Nsel):
        for j in range(Nsel):
            if result[j][1] == i:
                NewChrIx[i] = result[j][0]
                continue

    return NewChrIx

def across(Chrom,XOVR):
    NIND, WNumber2 = Chrom.shape
    WNumber = WNumber2/2
    WNumber = int(WNumber)
    NewChrom = np.zeros((NIND, WNumber2))
    for i in range(NIND):
        for j in range(WNumber2):
            NewChrom[i][j] = Chrom[i][j]

    SelNum = list(range(NIND))
    random.shuffle(SelNum)

    Num = int(NIND/2)

    for k in range(0,Num,2):
        Rand = random.random()
        if XOVR > Rand:
            Pos = random.randint(1,WNumber)   #交叉位置,randint闭区间
            while Pos == 1:
                Pos = random.randint(1,WNumber)

            S1 = np.zeros(WNumber)
            S2 = np.zeros(WNumber)
            for i in range(WNumber):
                S1[i] = Chrom[SelNum[k]][i]
                S2[i] = Chrom[SelNum[k+1]][i]

            S11 = np.zeros(WNumber)
            S22 = np.zeros(WNumber)
            for i in range(WNumber):
                S11[i] = S2[i]
                S22[i] = S1[i]

            for i in range(Pos):
                S11[i] = S1[i]
                S22[i] = S2[i]

            S3 = np.zeros(WNumber)
            S4 = np.zeros(WNumber)
            S5 = np.zeros(WNumber)
            S6 = np.zeros(WNumber)
            for i in range(WNumber):
                S3[i] = S11[i]
                S4[i] = S1[i]
                S5[i] = S22[i]
                S6[i] = S2[i]

            for j in range(WNumber):
                Pos1 = -1
                Pos2 = -1
                for i in range(WNumber):
                    if S4[i] == S3[j]:
                        Pos1 = i
                        break
                if Pos1 >= 0:
                    S3[j] = 0
                    S4[Pos1] = 0
                for i in range(WNumber):
                    if S6[i] == S5[j]:
                        Pos2 = i
                        break
                if Pos2 >= 0:
                    S5[j] = 0
                    S6[Pos2] = 0

            for j in range(WNumber):
                Pos1 = -1
                Pos2 = -1
                if S3[j] != 0:
                    for i in range(WNumber):
                        if S11[i] == S3[j]:
                            Pos1 = i
                            break
                    for i in range(WNumber):
                        if S4[i] != 0:
                            Pos2 = i
                            break
                    S11[Pos1] = S4[Pos2]
                    S4[Pos2] = 0

            for j in range(WNumber):
                Pos1 = -1
                Pos2 = -1
                if S5[j] != 0:
                    for i in range(WNumber):
                        if S22[i] == S5[j]:
                            Pos1 = i
                            break
                    for i in range(WNumber):
                        if S6[i] != 0:
                            Pos2 = i
                            break
                    S22[Pos1] = S6[Pos2]
                    S6[Pos2] = 0

            S1 = np.zeros(WNumber2)
            S2 = np.zeros(WNumber2)
            S111 = np.zeros(WNumber2)
            S222 = np.zeros(WNumber2)

            for i in range(WNumber2):
                S1[i] = Chrom[SelNum[k]][i]
                S2[i] = Chrom[SelNum[k+1]][i]
            for i in range(WNumber):
                S111[i] = S11[i]
                S222[i] = S22[i]

            for i in range(WNumber):
                Pos1 = -1
                Pos2 = -1
                for j in range(WNumber):
                    if S1[j] == S11[i]:
                        Pos1 = j
                        break
                S111[WNumber+i] = S1[WNumber+Pos1]
                S1[Pos1] = 0

                for j in range(WNumber):
                    if S2[j] == S22[i]:
                        Pos2 = j
                        break
                S222[WNumber+i] = S2[WNumber+Pos2]
                S2[Pos2] = 0

            for i in range(WNumber2):
                NewChrom[SelNum[k]][i] = S111[i]
                NewChrom[SelNum[k+1]][i] = S222[i]

    return NewChrom

def aberranceJm(Chrom,MUTR,Jm,T):
    NIND,WNumber2 = Chrom.shape
    WNumber = int(WNumber2/2)

    ChromNew = np.zeros((NIND,WNumber2))
    for i in range(NIND):
        for j in range(WNumber2):
            ChromNew[i][j] = Chrom[i][j]

    PNumber = Jm.shape[0]
    Number = np.ones(PNumber)

    S = np.zeros(WNumber2)
    WPNumberTemp = np.zeros(PNumber)
    for i in range(1):#NIND
        for j in range(WNumber):
            S[j] = Chrom[i][j]

        for j in range(PNumber):
            WPNumberTemp[j] = Number[j]

        #print(T)
        for j in range(2):#WNumber
            JMTemp = Jm[int(S[j])-1][int(WPNumberTemp[int(S[j])-1])-1]
            JMTempstr = str(JMTemp)
            if JMTempstr.isdigit():
                SizeTemp = 1
            else:
                SizeTemp = len(JMTemp)

            Rand = random.random()
            #print(T)                        #T已经变了
            if MUTR > Rand:
                if SizeTemp == 1:
                    S[j+WNumber] = 1
                else:
                    S_T = T[int(S[j])-1][int(WPNumberTemp[int(S[j])-1])-1]
                    S[j+WNumber] = selectJm(S[j+WNumber],S_T)

            WPNumberTemp[int(S[j])-1] = WPNumberTemp[int(S[j])-1] + 1

        for j in range(WNumber2):
            ChromNew[i][j] = S[j]

    return ChromNew

def selectJm(S,S_T):
    S_Tstr = str(S_T)
    if S_Tstr.isdigit():
        Num = 1
    else:
        Num = len(S_T)

    MaxVal = 0
    for i in range(Num):
        if S_T[i] > MaxVal:
            MaxVal = S_T[i]
    MaxVal = 2 * MaxVal

    S_TT = np.zeros(2)
    for i in range(Num):
        S_TT[i] = MaxVal - S_T[i]

    eVal = 0
    for i in range(Num):
        eVal = eVal + S_TT[i]

    P = np.zeros(Num)
    for i in range(Num):
        P[i] = S_TT[i]/eVal
    for i in range(Num-1):
        P[i+1] = P[i+1]+P[i]

    Rand = random.random()
    SelS = 1
    while Rand > P[SelS-1]:
        SelS = SelS + 1

    return SelS

def reins(Chrom, SelCh, SUBPOP, InsOpt, ObjVCh, ObjVSel):
    NIND, NvarP = Chrom.shape
    NSEL = SelCh.shape[0]
    NIns = min(NSEL,NIND)

    num_list = -ObjVCh
    ChIx = sorted(range(len(num_list)), key=lambda k: num_list[k])

    PopIx = np.zeros(NIns)
    for i in range(NIns):
        PopIx[i] = ChIx[i]

    if NIns <NSEL:
        num_list = ObjVSel
        OffIx = sorted(range(len(num_list)), key=lambda k: num_list[k])
    else:
        OffIx = np.zeros(NIns)
        for i in range(NIns):
            OffIx[i] = i + 1

    SelIx = np.zeros(NIns)
    for i in range(NIns):
        SelIx[i] = OffIx[i]


    for i in range(NIns):
        for j in range(NvarP):
            Chrom[int(PopIx[i])-1][j] = SelCh[int(SelIx[i])-1][j]

    for i in range(NIns):
        ObjVCh[int(PopIx[i])-1] = ObjVSel[int(SelIx[i])-1]

    return Chrom,ObjVCh

def plotRec(mPoint1,mPoint2,mText,val):
    vPoint = np.zeros((4,2))
    vPoint[0][0] = mPoint1
    vPoint[0][1] = mText-1
    vPoint[1][0] = mPoint2
    vPoint[1][1] = mText-1
    vPoint[2][0] = mPoint1
    vPoint[2][1] = mText
    vPoint[3][0] = mPoint2
    vPoint[3][1] = mText

    X = [vPoint[0][0],vPoint[1][0],vPoint[3][0],vPoint[2][0],vPoint[0][0]]
    Y = [vPoint[0][1],vPoint[1][1],vPoint[3][1],vPoint[2][1],vPoint[0][1]]
    plt.plot(X,Y,color='black')
    plt.text(mPoint1+0.1,mText-0.5,str(val),weight='bold',color='blue')

# 建制级装备级效能仿真算法
if __name__ == '__main__':
    ##三个接口——三行数据
    #Jm = np.array([[[1, 2], [3,5], 4], [[1, 2], [3,5], 4], [[1, 2], [3,5], 4], [[1, 2], [3,5], 4], [[1, 2], [3,5], 4]],dtype=object)  # 接口1——元胞数组
    Jm = np.array({{Jm}},dtype=object)  # 接口1——元胞数组
    #形状为5*3，5表示飞机数量，3表示每架飞机需要被保障3个点，数组内值为保障车编号
    #T = np.array([[[1, 4], [2,6], 4], [[3, 2], [4,5], 4], [[5, 4], [6,3], 1], [[5, 1], [5,5], 4], [[3, 1], [4,2], 1]],dtype=object)  # 接口2——元胞数组
    T = np.array({{T}},dtype=object)  # 接口2——元胞数组
    #形状、格式保持为和Jm一致，表示每种工作所花时间
    #JmNumber = 5  # 接口3——整数     保障车数量
    JmNumber = {{JmNumber}}  # 接口3——整数     保障车数量

    #POS = np.array([[0,1000],[300,500],[400,500],[500,500],[600,500],[700,500], [800,500]])     #仓库和5架飞机的坐标
    POS = np.array({{POS}})     #仓库和5架飞机的坐标
    #V = 600
    V = {{V}}

    #调用函数
    hanshu(Jm,T,JmNumber,POS,V)